mirror of
https://github.com/achlipala/frap.git
synced 2024-12-01 00:26:18 +00:00
SeparationLogic: example verifications
This commit is contained in:
parent
ef310e2b1e
commit
63be3681c8
1 changed files with 632 additions and 50 deletions
|
@ -207,6 +207,45 @@ Module Sep(Import S : SEP).
|
||||||
apply himp_heq in H0; intuition eauto.
|
apply himp_heq in H0; intuition eauto.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
Instance exis_imp_morphism (A : Type) :
|
||||||
|
Proper (pointwise_relation A himp ==> himp) (@exis A).
|
||||||
|
Proof.
|
||||||
|
hnf; intros.
|
||||||
|
apply exis_left; intro.
|
||||||
|
eapply exis_right.
|
||||||
|
unfold pointwise_relation in H.
|
||||||
|
eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma star_combine_lift1 : forall P Q, [| P |] * [| Q |] ===> [| P /\ Q |].
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
apply lift_left; intro.
|
||||||
|
rewrite extra_lift with (P := True); auto.
|
||||||
|
apply lift_left; intro.
|
||||||
|
rewrite extra_lift with (P := True) (p := [| P /\ Q |]); auto.
|
||||||
|
apply lift_right.
|
||||||
|
tauto.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma star_combine_lift2 : forall P Q, [| P /\ Q |] ===> [| P |] * [| Q |].
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
rewrite extra_lift with (P := True); auto.
|
||||||
|
apply lift_left; intro.
|
||||||
|
apply lift_right; try tauto.
|
||||||
|
rewrite extra_lift with (P := True) (p := [| P |]); auto.
|
||||||
|
apply lift_right; try tauto.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma star_combine_lift : forall P Q, [| P |] * [| Q |] === [| P /\ Q |].
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
apply himp_heq; auto using star_combine_lift1, star_combine_lift2.
|
||||||
|
Qed.
|
||||||
|
|
||||||
Lemma star_comm_lift : forall P q, [| P |] * q === q * [| P |].
|
Lemma star_comm_lift : forall P q, [| P |] * q === q * [| P |].
|
||||||
Proof.
|
Proof.
|
||||||
intros; apply star_comm.
|
intros; apply star_comm.
|
||||||
|
@ -262,6 +301,7 @@ Module Sep(Import S : SEP).
|
||||||
setoid_rewrite exis_gulp
|
setoid_rewrite exis_gulp
|
||||||
|| setoid_rewrite lift_combine
|
|| setoid_rewrite lift_combine
|
||||||
|| setoid_rewrite star_assoc
|
|| setoid_rewrite star_assoc
|
||||||
|
|| setoid_rewrite star_combine_lift
|
||||||
|| setoid_rewrite star_comm_lift
|
|| setoid_rewrite star_comm_lift
|
||||||
|| setoid_rewrite star_assoc_lift
|
|| setoid_rewrite star_assoc_lift
|
||||||
|| setoid_rewrite star_comm_exis.
|
|| setoid_rewrite star_comm_exis.
|
||||||
|
@ -269,7 +309,7 @@ Module Sep(Import S : SEP).
|
||||||
Ltac normalizeL :=
|
Ltac normalizeL :=
|
||||||
(apply exis_left || apply lift_left; intro; try congruence)
|
(apply exis_left || apply lift_left; intro; try congruence)
|
||||||
|| match goal with
|
|| match goal with
|
||||||
| [ |- [?P] ===> _ ] =>
|
| [ |- lift ?P ===> _ ] =>
|
||||||
match P with
|
match P with
|
||||||
| True => fail 1
|
| True => fail 1
|
||||||
| _ => apply lift1_left; intro; try congruence
|
| _ => apply lift1_left; intro; try congruence
|
||||||
|
@ -277,14 +317,15 @@ Module Sep(Import S : SEP).
|
||||||
end.
|
end.
|
||||||
|
|
||||||
Ltac normalizeR :=
|
Ltac normalizeR :=
|
||||||
eapply exis_right || apply lift_right
|
match goal with
|
||||||
|| match goal with
|
| [ |- _ ===> exis _ ] => eapply exis_right
|
||||||
| [ |- _ ===> [?Q] ] =>
|
| [ |- _ ===> _ * lift _ ] => apply lift_right
|
||||||
match Q with
|
| [ |- _ ===> lift ?Q ] =>
|
||||||
| True => fail 1
|
match Q with
|
||||||
| _ => apply lift1_right
|
| True => fail 1
|
||||||
end
|
| _ => apply lift1_right
|
||||||
end.
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
Ltac normalize1 := normalize0 || normalizeL || normalizeR.
|
Ltac normalize1 := normalize0 || normalizeL || normalizeR.
|
||||||
|
|
||||||
|
@ -308,13 +349,13 @@ Module Sep(Import S : SEP).
|
||||||
| [ H : ex _ |- _ ===> _ ] => destruct H
|
| [ H : ex _ |- _ ===> _ ] => destruct H
|
||||||
| [ H : _ /\ _ |- _ ] => destruct H
|
| [ H : _ /\ _ |- _ ] => destruct H
|
||||||
| [ H : _ = _ |- _ ] => rewrite H
|
| [ H : _ = _ |- _ ] => rewrite H
|
||||||
end; subst; subst rhs.
|
end; subst rhs.
|
||||||
|
|
||||||
Ltac normalize :=
|
Ltac normalize :=
|
||||||
simpl; intros; repeat normalize1; repeat normalize2;
|
simpl; intros; repeat normalize1; repeat normalize2;
|
||||||
repeat (match goal with
|
repeat (match goal with
|
||||||
| [ H : ex _ |- _ ===> _ ] => destruct H
|
| [ H : ex _ |- _ ===> _ ] => destruct H
|
||||||
end; intuition subst); subst.
|
end; intuition idtac).
|
||||||
|
|
||||||
Ltac forAllAtoms p k :=
|
Ltac forAllAtoms p k :=
|
||||||
match p with
|
match p with
|
||||||
|
@ -353,10 +394,121 @@ Module Sep(Import S : SEP).
|
||||||
| _ => progress autorewrite with core
|
| _ => progress autorewrite with core
|
||||||
end.
|
end.
|
||||||
|
|
||||||
Ltac cancel := normalize; repeat cancel1;
|
Ltac hide_evars :=
|
||||||
|
repeat match goal with
|
||||||
|
| [ |- ?P ===> _ ] => is_evar P; set P
|
||||||
|
| [ |- _ ===> ?Q ] => is_evar Q; set Q
|
||||||
|
| [ |- context[star ?P _] ] => is_evar P; set P
|
||||||
|
| [ |- context[star _ ?Q] ] => is_evar Q; set Q
|
||||||
|
| [ |- _ ===> (exists v, _ * ?R v) ] => is_evar R; set R
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac restore_evars :=
|
||||||
|
repeat match goal with
|
||||||
|
| [ x := _ |- _ ] => subst x
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint flattenAnds (Ps : list Prop) : Prop :=
|
||||||
|
match Ps with
|
||||||
|
| nil => True
|
||||||
|
| [P] => P
|
||||||
|
| P :: Ps => P /\ flattenAnds Ps
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac allPuresFrom k :=
|
||||||
|
match goal with
|
||||||
|
| [ H : ?P |- _ ] =>
|
||||||
|
match type of P with
|
||||||
|
| Prop => generalize dependent H; allPuresFrom ltac:(fun Ps => k (P :: Ps))
|
||||||
|
end
|
||||||
|
| _ => intros; k (@nil Prop)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac whichToQuantify skip foundAlready k :=
|
||||||
|
match goal with
|
||||||
|
| [ x : ?T |- _ ] =>
|
||||||
|
match type of T with
|
||||||
|
| Prop => fail 1
|
||||||
|
| _ =>
|
||||||
|
match skip with
|
||||||
|
| context[x] => fail 1
|
||||||
|
| _ =>
|
||||||
|
match foundAlready with
|
||||||
|
| context[x] => fail 1
|
||||||
|
| _ => (instantiate (1 := lift (x = x)); fail 2)
|
||||||
|
|| (instantiate (1 := fun _ => lift (x = x)); fail 2)
|
||||||
|
|| (whichToQuantify skip (x, foundAlready) k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
| _ => k foundAlready
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac quantifyOverThem vars e k :=
|
||||||
|
match vars with
|
||||||
|
| tt => k e
|
||||||
|
| (?x, ?vars') =>
|
||||||
|
match e with
|
||||||
|
| context[x] =>
|
||||||
|
match eval pattern x in e with
|
||||||
|
| ?f _ => quantifyOverThem vars' (exis f) k
|
||||||
|
end
|
||||||
|
| _ => quantifyOverThem vars' e k
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac addQuantifiers P k :=
|
||||||
|
whichToQuantify tt tt ltac:(fun vars =>
|
||||||
|
quantifyOverThem vars P k).
|
||||||
|
|
||||||
|
Ltac addQuantifiersSkipping x P k :=
|
||||||
|
whichToQuantify x tt ltac:(fun vars =>
|
||||||
|
quantifyOverThem vars P k).
|
||||||
|
|
||||||
|
Ltac basic_cancel :=
|
||||||
|
normalize; repeat cancel1; intuition eassumption.
|
||||||
|
|
||||||
|
Ltac cancel := hide_evars; normalize; repeat cancel1; restore_evars;
|
||||||
|
repeat match goal with
|
||||||
|
| [ H : True |- _ ] => clear H
|
||||||
|
end;
|
||||||
try match goal with
|
try match goal with
|
||||||
| [ |- _ ===> _ ] => intuition (try congruence)
|
| [ |- ?P ===> _ ] => sendToBack P;
|
||||||
end.
|
match goal with
|
||||||
|
| [ |- ?P ===> ?Q * ?P ] => is_evar Q;
|
||||||
|
rewrite (star_comm Q P);
|
||||||
|
allPuresFrom ltac:(fun Ps =>
|
||||||
|
match Ps with
|
||||||
|
| nil => instantiate (1 := lift True)
|
||||||
|
| _ =>
|
||||||
|
let Ps' := eval simpl in (flattenAnds Ps) in
|
||||||
|
addQuantifiers (lift Ps') ltac:(fun e => instantiate (1 := e))
|
||||||
|
end;
|
||||||
|
basic_cancel)
|
||||||
|
end
|
||||||
|
| [ |- ?P ===> ?Q ] => is_evar Q;
|
||||||
|
allPuresFrom ltac:(fun Ps =>
|
||||||
|
match Ps with
|
||||||
|
| nil => reflexivity
|
||||||
|
| _ =>
|
||||||
|
let Ps' := eval simpl in (flattenAnds Ps) in
|
||||||
|
addQuantifiers (star P (lift Ps')) ltac:(fun e => instantiate (1 := e));
|
||||||
|
basic_cancel
|
||||||
|
end)
|
||||||
|
| [ |- ?P ===> ?Q ?x ] => is_evar Q;
|
||||||
|
allPuresFrom ltac:(fun Ps =>
|
||||||
|
match Ps with
|
||||||
|
| nil => reflexivity
|
||||||
|
| _ =>
|
||||||
|
let Ps' := eval simpl in (flattenAnds Ps) in
|
||||||
|
addQuantifiersSkipping x (star P (lift Ps'))
|
||||||
|
ltac:(fun e => match eval pattern x in e with
|
||||||
|
| ?f _ => instantiate (1 := f)
|
||||||
|
end);
|
||||||
|
basic_cancel
|
||||||
|
end)
|
||||||
|
| [ |- _ ===> _ ] => intuition (try congruence)
|
||||||
|
end; intuition (try eassumption).
|
||||||
End Sep.
|
End Sep.
|
||||||
|
|
||||||
|
|
||||||
|
@ -535,24 +687,24 @@ Fixpoint zeroes (n : nat) : list nat :=
|
||||||
|
|
||||||
(** * Finally, the Hoare logic *)
|
(** * Finally, the Hoare logic *)
|
||||||
|
|
||||||
Inductive hoare_triple : assertion -> forall {result}, cmd result -> (result -> assertion) -> Prop :=
|
Inductive hoare_triple : forall {result}, assertion -> cmd result -> (result -> assertion) -> Prop :=
|
||||||
(* First, four basic rules that look exactly the same as before *)
|
(* First, four basic rules that look exactly the same as before *)
|
||||||
| HtReturn : forall P {result : Set} (v : result),
|
| HtReturn : forall P {result : Set} (v : result),
|
||||||
hoare_triple P (Return v) (fun r h => P h /\ r = v)
|
hoare_triple P (Return v) (fun r => P * [| r = v |])%sep
|
||||||
| HtBind : forall P {result' result} (c1 : cmd result') (c2 : result' -> cmd result) Q R,
|
| HtBind : forall P {result' result} (c1 : cmd result') (c2 : result' -> cmd result) Q R,
|
||||||
hoare_triple P c1 Q
|
hoare_triple P c1 Q
|
||||||
-> (forall r, hoare_triple (Q r) (c2 r) R)
|
-> (forall r, hoare_triple (Q r) (c2 r) R)
|
||||||
-> hoare_triple P (Bind c1 c2) R
|
-> hoare_triple P (Bind c1 c2) R
|
||||||
| HtLoop : forall {acc : Set} (init : acc) (body : acc -> cmd (loop_outcome acc)) I,
|
| HtLoop : forall {acc : Set} (init : acc) (body : acc -> cmd (loop_outcome acc)) I,
|
||||||
(forall acc, hoare_triple (I (Again acc)) (body acc) I)
|
(forall acc, hoare_triple (I (Again acc)) (body acc) I)
|
||||||
-> hoare_triple (I (Again init)) (Loop init body) (fun r h => I (Done r) h)
|
-> hoare_triple (I (Again init)) (Loop init body) (fun r => I (Done r))
|
||||||
| HtFail : forall {result},
|
| HtFail : forall {result},
|
||||||
hoare_triple (fun _ => False) (Fail (result := result)) (fun _ _ => False)
|
hoare_triple (fun _ => False) (Fail (result := result)) (fun _ _ => False)
|
||||||
|
|
||||||
| HtRead : forall a v,
|
| HtRead : forall a R,
|
||||||
hoare_triple (a |-> v)%sep (Read a) (fun r => a |-> v * [| r = v |])%sep
|
hoare_triple (exists v, a |-> v * R v)%sep (Read a) (fun r => a |-> r * R r)%sep
|
||||||
| HtWrite : forall a v',
|
| HtWrite : forall a v v',
|
||||||
hoare_triple (exists v, a |-> v)%sep (Write a v') (fun _ => a |-> v')%sep
|
hoare_triple (a |-> v)%sep (Write a v') (fun _ => a |-> v')%sep
|
||||||
| HtAlloc : forall numWords,
|
| HtAlloc : forall numWords,
|
||||||
hoare_triple emp%sep (Alloc numWords) (fun r => r |--> zeroes numWords)%sep
|
hoare_triple emp%sep (Alloc numWords) (fun r => r |--> zeroes numWords)%sep
|
||||||
| HtFree : forall a numWords,
|
| HtFree : forall a numWords,
|
||||||
|
@ -567,12 +719,13 @@ Inductive hoare_triple : assertion -> forall {result}, cmd result -> (result ->
|
||||||
hoare_triple P c Q
|
hoare_triple P c Q
|
||||||
-> hoare_triple (P * R)%sep c (fun r => Q r * R)%sep.
|
-> hoare_triple (P * R)%sep c (fun r => Q r * R)%sep.
|
||||||
|
|
||||||
|
|
||||||
Notation "{{ P }} c {{ r ~> Q }}" :=
|
Notation "{{ P }} c {{ r ~> Q }}" :=
|
||||||
(hoare_triple P%sep c (fun r => Q%sep)) (at level 90, c at next level).
|
(hoare_triple P%sep c (fun r => Q%sep)) (at level 90, c at next level).
|
||||||
|
|
||||||
Lemma HtStrengthen : forall {result} (c : cmd result) P Q (Q' : _ -> assertion),
|
Lemma HtStrengthen : forall {result} (c : cmd result) P Q (Q' : _ -> assertion),
|
||||||
hoare_triple P c Q
|
hoare_triple P c Q
|
||||||
-> (forall r h, Q r h -> Q' r h)
|
-> (forall r, Q r ===> Q' r)
|
||||||
-> hoare_triple P c Q'.
|
-> hoare_triple P c Q'.
|
||||||
Proof.
|
Proof.
|
||||||
simplify.
|
simplify.
|
||||||
|
@ -582,7 +735,7 @@ Qed.
|
||||||
|
|
||||||
Lemma HtWeaken : forall {result} (c : cmd result) P Q (P' : assertion),
|
Lemma HtWeaken : forall {result} (c : cmd result) P Q (P' : assertion),
|
||||||
hoare_triple P c Q
|
hoare_triple P c Q
|
||||||
-> (forall h, P' h -> P h)
|
-> P' ===> P
|
||||||
-> hoare_triple P' c Q.
|
-> hoare_triple P' c Q.
|
||||||
Proof.
|
Proof.
|
||||||
simplify.
|
simplify.
|
||||||
|
@ -596,11 +749,16 @@ Lemma invert_Return : forall {result : Set} (r : result) P Q,
|
||||||
Proof.
|
Proof.
|
||||||
induct 1; propositional; eauto.
|
induct 1; propositional; eauto.
|
||||||
|
|
||||||
|
exists h, $0; propositional; eauto.
|
||||||
|
unfold lift; propositional.
|
||||||
|
|
||||||
unfold himp in *; eauto.
|
unfold himp in *; eauto.
|
||||||
|
|
||||||
unfold star, himp in *; simp; eauto 7.
|
unfold star, himp in *; simp; eauto 7.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
Hint Constructors hoare_triple.
|
||||||
|
|
||||||
Lemma invert_Bind : forall {result' result} (c1 : cmd result') (c2 : result' -> cmd result) P Q,
|
Lemma invert_Bind : forall {result' result} (c1 : cmd result') (c2 : result' -> cmd result) P Q,
|
||||||
hoare_triple P (Bind c1 c2) Q
|
hoare_triple P (Bind c1 c2) Q
|
||||||
-> exists R, hoare_triple P c1 R
|
-> exists R, hoare_triple P c1 R
|
||||||
|
@ -624,8 +782,6 @@ Proof.
|
||||||
eapply HtFrame; eauto.
|
eapply HtFrame; eauto.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
Hint Constructors hoare_triple.
|
|
||||||
|
|
||||||
Lemma invert_Loop : forall {acc : Set} (init : acc) (body : acc -> cmd (loop_outcome acc)) P Q,
|
Lemma invert_Loop : forall {acc : Set} (init : acc) (body : acc -> cmd (loop_outcome acc)) P Q,
|
||||||
hoare_triple P (Loop init body) Q
|
hoare_triple P (Loop init body) Q
|
||||||
-> exists I, (forall acc, hoare_triple (I (Again acc)) (body acc) I)
|
-> exists I, (forall acc, hoare_triple (I (Again acc)) (body acc) I)
|
||||||
|
@ -671,12 +827,12 @@ Qed.
|
||||||
|
|
||||||
Lemma invert_Read : forall a P Q,
|
Lemma invert_Read : forall a P Q,
|
||||||
hoare_triple P (Read a) Q
|
hoare_triple P (Read a) Q
|
||||||
-> exists v R, (P ===> a |-> v * R)%sep
|
-> exists R, (P ===> exists v, a |-> v * R v)%sep
|
||||||
/\ a |-> v * R ===> Q v.
|
/\ forall r, a |-> r * R r ===> Q r.
|
||||||
Proof.
|
Proof.
|
||||||
induct 1; simp; eauto.
|
induct 1; simp; eauto.
|
||||||
|
|
||||||
exists v, emp; simp.
|
exists R; simp.
|
||||||
cancel; auto.
|
cancel; auto.
|
||||||
cancel; auto.
|
cancel; auto.
|
||||||
|
|
||||||
|
@ -686,9 +842,11 @@ Proof.
|
||||||
|
|
||||||
eauto 7 using himp_trans.
|
eauto 7 using himp_trans.
|
||||||
|
|
||||||
exists x, (x0 * R)%sep; simp.
|
exists (fun n => x n * R)%sep; simp.
|
||||||
|
rewrite H1.
|
||||||
cancel.
|
cancel.
|
||||||
|
|
||||||
|
rewrite <- H2.
|
||||||
cancel.
|
cancel.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
@ -932,6 +1090,17 @@ Proof.
|
||||||
assumption.
|
assumption.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
Lemma HtReturn' : forall P {result : Set} (v : result) Q,
|
||||||
|
P ===> Q v
|
||||||
|
-> hoare_triple P (Return v) Q.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
eapply HtStrengthen.
|
||||||
|
constructor.
|
||||||
|
simp.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
(* Temporarily transparent again! *)
|
(* Temporarily transparent again! *)
|
||||||
Transparent heq himp lift star exis ptsto.
|
Transparent heq himp lift star exis ptsto.
|
||||||
|
|
||||||
|
@ -955,24 +1124,21 @@ Proof.
|
||||||
assumption.
|
assumption.
|
||||||
simp.
|
simp.
|
||||||
cases r.
|
cases r.
|
||||||
|
apply HtReturn'.
|
||||||
|
unfold himp; simp; eauto.
|
||||||
eapply HtStrengthen.
|
eapply HtStrengthen.
|
||||||
eauto.
|
eauto.
|
||||||
simp; eauto.
|
unfold himp; simp; eauto.
|
||||||
eapply HtStrengthen.
|
|
||||||
eauto.
|
|
||||||
simp; eauto.
|
|
||||||
|
|
||||||
apply invert_Read in H0; simp.
|
apply invert_Read in H0; simp.
|
||||||
eapply HtStrengthen.
|
apply HtReturn'.
|
||||||
econstructor.
|
assert ((exists v, a |-> v * x v)%sep h') by auto.
|
||||||
simp.
|
unfold exis, star in H1; simp.
|
||||||
assert ((a |-> x * x0)%sep h') by auto.
|
|
||||||
unfold star in H0; simp.
|
|
||||||
unfold ptsto in H4; subst.
|
unfold ptsto in H4; subst.
|
||||||
unfold split in H3; subst.
|
unfold split in H1; subst.
|
||||||
unfold heap1 in H.
|
unfold heap1 in H.
|
||||||
rewrite lookup_join1 in H by (simp; sets).
|
rewrite lookup_join1 in H by (simp; sets).
|
||||||
simp.
|
unfold himp; simp.
|
||||||
invert H.
|
invert H.
|
||||||
apply H2.
|
apply H2.
|
||||||
unfold star.
|
unfold star.
|
||||||
|
@ -981,8 +1147,7 @@ Proof.
|
||||||
unfold ptsto; reflexivity.
|
unfold ptsto; reflexivity.
|
||||||
|
|
||||||
apply invert_Write in H0; simp.
|
apply invert_Write in H0; simp.
|
||||||
eapply HtStrengthen.
|
apply HtReturn'.
|
||||||
econstructor.
|
|
||||||
simp.
|
simp.
|
||||||
assert (((exists v : nat, a |-> v) * x)%sep h) by auto.
|
assert (((exists v : nat, a |-> v) * x)%sep h) by auto.
|
||||||
unfold star in H1; simp.
|
unfold star in H1; simp.
|
||||||
|
@ -991,7 +1156,7 @@ Proof.
|
||||||
unfold split in H3; subst.
|
unfold split in H3; subst.
|
||||||
unfold heap1 in H.
|
unfold heap1 in H.
|
||||||
rewrite lookup_join1 in H by (simp; sets).
|
rewrite lookup_join1 in H by (simp; sets).
|
||||||
simp.
|
unfold himp; simp.
|
||||||
invert H.
|
invert H.
|
||||||
apply H2.
|
apply H2.
|
||||||
unfold star.
|
unfold star.
|
||||||
|
@ -1011,18 +1176,16 @@ Proof.
|
||||||
unfold ptsto; reflexivity.
|
unfold ptsto; reflexivity.
|
||||||
|
|
||||||
apply invert_Alloc with (r := a) in H0.
|
apply invert_Alloc with (r := a) in H0.
|
||||||
eapply HtStrengthen.
|
apply HtReturn'.
|
||||||
econstructor.
|
unfold himp; simp.
|
||||||
simp.
|
|
||||||
eapply himp_trans in H0; try apply zeroes_initialize.
|
eapply himp_trans in H0; try apply zeroes_initialize.
|
||||||
auto.
|
auto.
|
||||||
assumption.
|
assumption.
|
||||||
|
|
||||||
apply invert_Free in H.
|
apply invert_Free in H.
|
||||||
assert (((exists vs : list nat, a |--> vs * [|Datatypes.length vs = numWords|]) * Q tt)%sep h) by auto.
|
assert (((exists vs : list nat, a |--> vs * [|Datatypes.length vs = numWords|]) * Q tt)%sep h) by auto.
|
||||||
eapply HtStrengthen.
|
apply HtReturn'.
|
||||||
econstructor.
|
unfold himp; simp.
|
||||||
simp.
|
|
||||||
eapply do_deallocate.
|
eapply do_deallocate.
|
||||||
eauto.
|
eauto.
|
||||||
Qed.
|
Qed.
|
||||||
|
@ -1071,9 +1234,16 @@ Proof.
|
||||||
| [ H : forall _ h1 _, _ -> _ -> ?P h1 -> _, H' : ?P _ |- _ ] => eapply H in H'; clear H; try eassumption; simp
|
| [ H : forall _ h1 _, _ -> _ -> ?P h1 -> _, H' : ?P _ |- _ ] => eapply H in H'; clear H; try eassumption; simp
|
||||||
end; eauto.
|
end; eauto.
|
||||||
|
|
||||||
right; exists h, (Return v).
|
invert H1.
|
||||||
|
right; exists h, (Return x0).
|
||||||
constructor.
|
constructor.
|
||||||
unfold split, ptsto, heap1 in *; simp.
|
unfold split, ptsto, heap1 in *; simp.
|
||||||
|
unfold star in H2; simp.
|
||||||
|
unfold split in H; simp.
|
||||||
|
rewrite lookup_join1; simp.
|
||||||
|
rewrite lookup_join1; simp.
|
||||||
|
sets.
|
||||||
|
eapply lookup_Some_dom.
|
||||||
rewrite lookup_join1; simp.
|
rewrite lookup_join1; simp.
|
||||||
sets.
|
sets.
|
||||||
|
|
||||||
|
@ -1166,3 +1336,415 @@ Proof.
|
||||||
assert (exists bound, forall a, a >= bound -> fst s $? a = None) by eauto.
|
assert (exists bound, forall a, a >= bound -> fst s $? a = None) by eauto.
|
||||||
cases s; simp; eauto.
|
cases s; simp; eauto.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
(* Fancy theorem to help us rewrite within preconditions and postconditions *)
|
||||||
|
Instance hoare_triple_morphism : forall A,
|
||||||
|
Proper (heq ==> eq ==> (eq ==> heq) ==> iff) (@hoare_triple A).
|
||||||
|
Proof.
|
||||||
|
Transparent himp.
|
||||||
|
repeat (hnf; intros).
|
||||||
|
unfold pointwise_relation in *; intuition subst.
|
||||||
|
|
||||||
|
eapply HtConsequence; eauto.
|
||||||
|
rewrite H; reflexivity.
|
||||||
|
intros.
|
||||||
|
hnf in H1.
|
||||||
|
specialize (H1 r _ eq_refl).
|
||||||
|
rewrite H1; reflexivity.
|
||||||
|
|
||||||
|
eapply HtConsequence; eauto.
|
||||||
|
rewrite H; reflexivity.
|
||||||
|
intros.
|
||||||
|
hnf in H1.
|
||||||
|
specialize (H1 r _ eq_refl).
|
||||||
|
rewrite H1; reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(** * Examples *)
|
||||||
|
|
||||||
|
Opaque heq himp lift star exis ptsto.
|
||||||
|
|
||||||
|
Theorem use_lemma : forall result P' (c : cmd result) (Q : result -> assertion) P R,
|
||||||
|
hoare_triple P' c Q
|
||||||
|
-> P ===> P' * R
|
||||||
|
-> hoare_triple P c (fun r => Q r * R)%sep.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
eapply HtWeaken.
|
||||||
|
eapply HtFrame.
|
||||||
|
eassumption.
|
||||||
|
eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem HtRead' : forall a v,
|
||||||
|
hoare_triple (a |-> v)%sep (Read a) (fun r => a |-> v * [| r = v |])%sep.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
apply HtWeaken with (exists r, a |-> r * [| r = v |])%sep.
|
||||||
|
eapply HtStrengthen.
|
||||||
|
apply HtRead.
|
||||||
|
simp.
|
||||||
|
cancel; auto.
|
||||||
|
subst; cancel.
|
||||||
|
cancel; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem HtRead'' : forall p P R,
|
||||||
|
P ===> (exists v, p |-> v * R v)
|
||||||
|
-> hoare_triple P (Read p) (fun r => p |-> r * R r)%sep.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
eapply HtWeaken.
|
||||||
|
apply HtRead.
|
||||||
|
assumption.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Ltac basic := apply HtReturn' || eapply HtRead' || eapply HtWrite || eapply HtAlloc
|
||||||
|
|| (eapply HtRead''; solve [ cancel ]).
|
||||||
|
|
||||||
|
Ltac step0 := basic || eapply HtBind || (eapply use_lemma; [ basic | cancel; auto ])
|
||||||
|
|| (eapply HtStrengthen; [ eapply use_lemma; [ basic | cancel; auto ] | ])
|
||||||
|
|| (eapply HtConsequence; [ apply HtFail | .. ]).
|
||||||
|
Ltac step := step0; simp.
|
||||||
|
Ltac ht := simp; repeat step.
|
||||||
|
Ltac conseq := simplify; eapply HtConsequence.
|
||||||
|
Ltac use_IH H := conseq; [ apply H | .. ]; ht.
|
||||||
|
Ltac loop_inv0 Inv := (eapply HtWeaken; [ apply HtLoop with (I := Inv) | .. ])
|
||||||
|
|| (eapply HtConsequence; [ apply HtLoop with (I := Inv) | .. ]).
|
||||||
|
Ltac loop_inv Inv := loop_inv0 Inv; ht.
|
||||||
|
Ltac use H := (eapply use_lemma; [ eapply H | cancel; auto ])
|
||||||
|
|| (eapply HtStrengthen; [ eapply use_lemma; [ eapply H | cancel; auto ] | ]).
|
||||||
|
|
||||||
|
Ltac heq := intros; apply himp_heq; split.
|
||||||
|
|
||||||
|
(** ** Swapping with two pointers *)
|
||||||
|
|
||||||
|
Definition swap p q :=
|
||||||
|
tmpp <- Read p;
|
||||||
|
tmpq <- Read q;
|
||||||
|
_ <- Write p tmpq;
|
||||||
|
Write q tmpp.
|
||||||
|
|
||||||
|
Theorem swap_ok : forall p q a b,
|
||||||
|
{{p |-> a * q |-> b}}
|
||||||
|
swap p q
|
||||||
|
{{_ ~> p |-> b * q |-> a}}.
|
||||||
|
Proof.
|
||||||
|
unfold swap.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
subst.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Opaque swap.
|
||||||
|
|
||||||
|
Definition rotate p q r :=
|
||||||
|
_ <- swap p q;
|
||||||
|
swap q r.
|
||||||
|
|
||||||
|
Theorem rotate_ok : forall p q r a b c,
|
||||||
|
{{p |-> a * q |-> b * r |-> c}}
|
||||||
|
rotate p q r
|
||||||
|
{{_ ~> p |-> b * q |-> c * r |-> a}}.
|
||||||
|
Proof.
|
||||||
|
unfold rotate.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
use swap_ok.
|
||||||
|
simp.
|
||||||
|
use swap_ok.
|
||||||
|
simp.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Opaque rotate.
|
||||||
|
|
||||||
|
(** ** Initializing a fresh object *)
|
||||||
|
|
||||||
|
Definition init :=
|
||||||
|
p <- Alloc 2;
|
||||||
|
_ <- Write p 7;
|
||||||
|
_ <- Write (p+1) 8;
|
||||||
|
Return p.
|
||||||
|
|
||||||
|
Theorem init_ok :
|
||||||
|
{{emp}}
|
||||||
|
init
|
||||||
|
{{p ~> p |--> [7; 8]}}.
|
||||||
|
Proof.
|
||||||
|
unfold init.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Opaque init.
|
||||||
|
|
||||||
|
Theorem ultra_combo_ok :
|
||||||
|
{{emp}}
|
||||||
|
p <- init;
|
||||||
|
_ <- swap p (p+1);
|
||||||
|
Return p
|
||||||
|
{{p ~> p |--> [8; 7]}}.
|
||||||
|
Proof.
|
||||||
|
step.
|
||||||
|
use init_ok.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
use swap_ok.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** In-place reversal of a singly linked list *)
|
||||||
|
|
||||||
|
(* Let's give a recursive definition of how a linked list should be laid out in
|
||||||
|
* memory. *)
|
||||||
|
Fixpoint linkedList (p : nat) (ls : list nat) :=
|
||||||
|
match ls with
|
||||||
|
| nil => [| p = 0 |]
|
||||||
|
(* An empty list is associated with a null pointer and no memory
|
||||||
|
* contents. *)
|
||||||
|
| x :: ls' => [| p <> 0 |]
|
||||||
|
* exists p', p |-> x * (p+1) |-> p' * linkedList p' ls'
|
||||||
|
(* A nonempty list is associated with a nonnull pointer and a two-cell
|
||||||
|
* struct, which points to a further list. *)
|
||||||
|
end%sep.
|
||||||
|
|
||||||
|
(* The definition of [linkedList] is recursive in the list. Let's also prove
|
||||||
|
* lemmas for simplifying [linkedList] invocations based on values of [p]. *)
|
||||||
|
|
||||||
|
Theorem linkedList_null : forall ls,
|
||||||
|
linkedList 0 ls === [| ls = nil |].
|
||||||
|
Proof.
|
||||||
|
heq; destruct ls; cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem linkedList_nonnull : forall p ls,
|
||||||
|
p <> 0
|
||||||
|
-> linkedList p ls === exists x ls' p', [| ls = x :: ls' |] * p |-> x * (p+1) |-> p' * linkedList p' ls'.
|
||||||
|
Proof.
|
||||||
|
heq; destruct ls; cancel.
|
||||||
|
invert H0; cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Hint Rewrite <- rev_alt.
|
||||||
|
Hint Rewrite rev_involutive.
|
||||||
|
|
||||||
|
(* Let's hide the definition of [linkedList], so that we *only* reason about it
|
||||||
|
* via the two lemmas we just proved. *)
|
||||||
|
Opaque linkedList.
|
||||||
|
|
||||||
|
Definition reverse p :=
|
||||||
|
pr <- for pr := (p, 0) loop
|
||||||
|
let (p, r) := pr in
|
||||||
|
if p ==n 0 then
|
||||||
|
Return (Done pr)
|
||||||
|
else
|
||||||
|
tmp <- Read (p + 1);
|
||||||
|
_ <- Write (p+1) r;
|
||||||
|
Return (Again (tmp, p))
|
||||||
|
done;
|
||||||
|
Return (snd pr).
|
||||||
|
|
||||||
|
Definition valueOf {A} (o : loop_outcome A) :=
|
||||||
|
match o with
|
||||||
|
| Done v => v
|
||||||
|
| Again v => v
|
||||||
|
end.
|
||||||
|
|
||||||
|
Opaque himp.
|
||||||
|
|
||||||
|
(* Finally, it's correct. *)
|
||||||
|
|
||||||
|
Theorem reverse_ok : forall p ls,
|
||||||
|
{{linkedList p ls}}
|
||||||
|
reverse p
|
||||||
|
{{r ~> linkedList r (rev ls)}}.
|
||||||
|
Proof.
|
||||||
|
unfold reverse.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
loop_inv (fun o => exists ls1 ls2, [| ls = rev_append ls1 ls2 |]
|
||||||
|
* linkedList (fst (valueOf o)) ls2
|
||||||
|
* linkedList (snd (valueOf o)) ls1
|
||||||
|
* [| match o with
|
||||||
|
| Done (p, _) => p = 0
|
||||||
|
| _ => True
|
||||||
|
end |])%sep.
|
||||||
|
cases (a ==n 0); simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
step.
|
||||||
|
setoid_rewrite (linkedList_nonnull _ n).
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
setoid_rewrite (linkedList_nonnull _ n).
|
||||||
|
cancel.
|
||||||
|
simp.
|
||||||
|
setoid_rewrite linkedList_null.
|
||||||
|
cancel.
|
||||||
|
equality.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
simp.
|
||||||
|
setoid_rewrite linkedList_null.
|
||||||
|
cancel.
|
||||||
|
simp.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Opaque reverse.
|
||||||
|
|
||||||
|
(* ** Calling [reverse] twice, to illustrate the *frame rule* *)
|
||||||
|
|
||||||
|
Theorem reverse_two_ok : forall p1 ls1 p2 ls2,
|
||||||
|
{{linkedList p1 ls1 * linkedList p2 ls2}}
|
||||||
|
p1 <- reverse p1;
|
||||||
|
p2 <- reverse p2;
|
||||||
|
Return (p1, p2)
|
||||||
|
{{ps ~> linkedList (fst ps) (rev ls1) * linkedList (snd ps) (rev ls2)}}.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
use reverse_ok.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
use reverse_ok.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ** Computing the length of a linked list *)
|
||||||
|
|
||||||
|
(* To state a good loop invariant, it will be helpful to define
|
||||||
|
* *list segments* that end with some pointer beside null. *)
|
||||||
|
Fixpoint linkedListSegment (p : nat) (ls : list nat) (q : nat) :=
|
||||||
|
match ls with
|
||||||
|
| nil => [| p = q |]
|
||||||
|
| x :: ls' => [| p <> 0 |] * exists p', p |-> x * (p+1) |-> p' * linkedListSegment p' ls' q
|
||||||
|
end%sep.
|
||||||
|
|
||||||
|
(* Next, two [linkedListSegment] lemmas analogous to those for [linkedList]
|
||||||
|
* above *)
|
||||||
|
|
||||||
|
Lemma linkedListSegment_empty : forall p ls,
|
||||||
|
linkedList p ls ===> linkedList p ls * linkedListSegment p nil p.
|
||||||
|
Proof.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma linkedListSegment_append : forall q r x ls p,
|
||||||
|
q <> 0
|
||||||
|
-> linkedListSegment p ls q * q |-> x * (q+1) |-> r ===> linkedListSegment p (ls ++ x :: nil) r.
|
||||||
|
Proof.
|
||||||
|
induction ls; cancel; auto.
|
||||||
|
subst; cancel.
|
||||||
|
rewrite <- IHls; cancel; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(* One more [linkedList] lemma will be helpful. We'll re-reveal the predicate's
|
||||||
|
* definition to prove the lemma. *)
|
||||||
|
|
||||||
|
Transparent linkedList.
|
||||||
|
|
||||||
|
Lemma linkedListSegment_null : forall ls p,
|
||||||
|
linkedListSegment p ls 0 ===> linkedList p ls.
|
||||||
|
Proof.
|
||||||
|
induction ls; cancel; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Opaque linkedList linkedListSegment.
|
||||||
|
|
||||||
|
Hint Rewrite <- app_assoc.
|
||||||
|
Hint Rewrite app_length app_nil_r.
|
||||||
|
|
||||||
|
Lemma move_along : forall A (ls : list A) x2 x1 x0 x,
|
||||||
|
ls = x2 ++ x1
|
||||||
|
-> x1 = x0 :: x
|
||||||
|
-> ls = (x2 ++ [x0]) ++ x.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Hint Resolve move_along.
|
||||||
|
|
||||||
|
(* Finally, this code is correct. *)
|
||||||
|
Theorem length_ok : forall p ls,
|
||||||
|
{{linkedList p ls}}
|
||||||
|
q_len <- for q_len := (p, 0) loop
|
||||||
|
let (q, len) := q_len in
|
||||||
|
if q ==n 0 then
|
||||||
|
Return (Done q_len)
|
||||||
|
else
|
||||||
|
tmp <- Read (q + 1);
|
||||||
|
Return (Again (tmp, len+1))
|
||||||
|
done;
|
||||||
|
Return (snd q_len)
|
||||||
|
{{len ~> linkedList p ls * [| len = length ls |]}}.
|
||||||
|
Proof.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
loop_inv (fun o => exists ls1 ls2, [| ls = ls1 ++ ls2 |]
|
||||||
|
* linkedListSegment p ls1 (fst (valueOf o))
|
||||||
|
* linkedList (fst (valueOf o)) ls2
|
||||||
|
* [| snd (valueOf o) = length ls1 |]
|
||||||
|
* [| match o with
|
||||||
|
| Done (q, _) => q = 0 /\ ls2 = nil
|
||||||
|
| _ => True
|
||||||
|
end |])%sep.
|
||||||
|
cases (a ==n 0); simp.
|
||||||
|
step.
|
||||||
|
setoid_rewrite linkedList_null.
|
||||||
|
cancel.
|
||||||
|
step.
|
||||||
|
setoid_rewrite (linkedList_nonnull _ n).
|
||||||
|
step.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
eauto.
|
||||||
|
simp.
|
||||||
|
setoid_rewrite <- linkedListSegment_append.
|
||||||
|
cancel.
|
||||||
|
auto.
|
||||||
|
rewrite linkedListSegment_empty.
|
||||||
|
cancel.
|
||||||
|
simp.
|
||||||
|
step.
|
||||||
|
cancel.
|
||||||
|
simp.
|
||||||
|
simp.
|
||||||
|
rewrite linkedListSegment_null.
|
||||||
|
rewrite linkedList_null.
|
||||||
|
cancel.
|
||||||
|
Qed.
|
||||||
|
|
Loading…
Reference in a new issue