Library sgoto_hoare
Require Import Lia.
From mathcomp Require Import ssreflect ssrbool.
Require while.
Require Import goto sgoto.
From mathcomp Require Import ssreflect ssrbool.
Require while.
Require Import goto sgoto.
Hoare Logic of SGoto
Declare Scope sgoto_hoare_scope.
Module SGoto_Hoare (while_hoare_deter_m : while.WHILE_HOARE_DETER).
Module Import sgoto_m := SGoto while_hoare_deter_m.
Import goto_deter_m.
Import goto_m.
Import while_hoare_deter_m.
Definition assn := label -> assert.
Local Open Scope while_assert_scope.
Definition restrict (P : assn) d : assn := fun l => P l //\\ (fun _ _ => List.In l d).
Definition restrict_cplt (P : assn) d : assn := fun l => while.Not (fun _ _ => List.In l d) //\\ P l.
Lemma restrict_dom : forall l d (P : assn) s h, List.In l d -> P l s h -> restrict P d l s h.
Proof. done. Qed.
Lemma restrict_cplt_dom : forall (P : assn) l s h d, P l s h -> ~ List.In l d -> restrict_cplt P d l s h.
Proof. done. Qed.
Reserved Notation "'[^' P '^]' c '[^' Q '^]'" (at level 82, no associativity).
Figure 3 (Hoare rules of SGoto) in [Saabas&Uustalu2007].
Local Open Scope sgoto_scope.
Notation "'_assn'" := assn : sgoto_hoare_scope. Local Open Scope sgoto_hoare_scope.
Inductive hoare_sgoto : assn -> scode -> assn -> Prop :=
| hoare_cmd : forall l c P,
[^ fun pc => fun s h => pc = l /\ (wp0 c (P (S l))) s h \/ pc <> l /\ P pc s h ^]
sC l c [^ P ^]
| hoare_jmp : forall l j Q,
[^ fun pc => fun s h => pc = l /\ (Q j s h \/ j = l) \/ pc <> l /\ Q pc s h ^]
sB l (jmp j) [^ Q ^]
| hoare_branch : forall l b j Q,
[^ fun pc => fun s h =>
pc = l /\ (~~ eval_b b (s, h) /\ Q (S l) s h \/ eval_b b (s, h) /\ ( Q j s h \/ j = l)) \/
pc <> l /\ Q pc s h ^]
sB l (cjmp b j) [^ Q ^]
| hoare_sO : forall P, [^ P ^] sO [^ P ^]
| hoare_sS : forall sc0 sc1 P,
[^ restrict P (sdom sc0) ^] sc0 [^ P ^] -> [^ restrict P (sdom sc1) ^] sc1 [^ P ^] ->
[^ P ^] sc0 [+] sc1 [^ restrict_cplt P (sdom (sc0 [+] sc1)) ^]
| hoare_sgoto_conseq : forall sc (P Q P' Q': assn),
(forall l, P l ===> P' l) -> (forall l, Q' l ===> Q l) ->
[^ P' ^] sc [^ Q' ^] -> [^ P ^] sc [^ Q ^]
where "'[^' P '^]' c '[^' Q '^]'" := (hoare_sgoto P c Q) : sgoto_hoare_scope.
Theorem 10 (Soundness) in [Saabas&Uustalu2007]:
Module while_semop_prop_m := while.While_Semop_Prop while_hoare_deter_m.
Lemma hoare_sgoto_sound : forall sc P Q, [^ P ^] sc [^ Q ^] ->
forall l s h, P l s h -> ~ (Some (l, (s, h)) >- sc ---> None) /\
forall l' s' h', Some (l, (s, h)) >- sc ---> Some (l', (s', h')) -> Q l' s' h'.
Proof.
move=> sc Pi Pi'; elim=> //=; clear sc Pi Pi'.
- move=> l c Pi l0 s0 h0 [ [l0_l X2] | [l0_l X2] ]; split.
+ subst l0 => X.
inversion X; subst.
inversion H3; subst.
by move: (wp0_no_err _ _ _ _ X2).
+ move=> l' s' h' Hexec; subst l0.
case/(exec_sgoto_inv_cmd _ _ _ _ _) : Hexec => X; subst.
move/while_semop_prop_m.exec_cmd0_inv => Hexec.
by eapply exec0_wp0; [apply Hexec | exact X2].
+ move=> X; inversion X; by subst.
+ move=> l' s' h'.
move/(exec_sgoto_inv_refl _ _ _ _) => H.
have : ~ List.In l0 (sdom (sC l c)) by rewrite /=; intuition.
by case/H => ? ?; subst => <-.
- move=> l j Q l0 s0 h0 [ [l0_l [X2 | X2] ] | [l0_l X2] ]; split.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec; subst l.
by case/(exec_sgoto_inv_jmp _ _ _ _) : Hexec; case=> ? ? ? _; subst.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec; subst.
inversion Hexec; subst => //.
rewrite /= in H1; tauto.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec.
apply exec_sgoto_inv_refl in Hexec.
* case: Hexec => K1 K2 K3; by subst.
* rewrite /=; contradict l0_l; by case: l0_l.
- move=> l b j Q l0 s0 h0 [[l0_l [ [X3 HQ] | [X2 [X3|j_l] ] ] ] | [l0_l HQ] ]; split.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec; subst l.
by case: {Hexec}(exec_sgoto_inv_cjmp_false _ _ _ _ _ Hexec X3) => ? ? ?; subst.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec; subst l.
case: {Hexec}(exec_sgoto_inv_cjmp_true _ _ _ _ _ Hexec X2); case => X Y Z _; by subst.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec; subst.
inversion Hexec; subst => //.
by rewrite X2 in H0.
rewrite /= in H1; tauto.
+ by move=> X; inversion X.
+ move=> l' s' h' Hexec.
move: (exec_sgoto_inv_refl _ _ _ _ Hexec) => H.
have : ~ List.In l0 (sdom (sB l (cjmp b j))) by rewrite /=; intuition.
case/H=> K1 K2 K3; by subst.
- move=> Pi l0 s0 h0 HPil0; split.
+ by move=> X; inversion X.
+ move=> l' s' h'.
move/(exec_sgoto_inv_refl _ _ _ _) => /= X.
have : ~ False by tauto.
case/X => Y Z V; by subst.
- move=> sc1 sc2 P Hsc0 IHsc0 Hsc1 IHsc1 l0 s0 h0 HP_l0; split.
+ move Hst0 : (Some (l0, (s0, h0))) => st0.
move Hst' : None => st'.
move Hsc : (sc1 [+] sc2) => sc.
move=> Hexec.
move: Hexec sc1 sc2 P Hsc0 IHsc0 Hsc1 IHsc1 Hsc l0 s0 h0 HP_l0 Hst0 Hst'.
elim => //; move=> {sc st0 st'}.
+ move=> sc1 sc2 l0 st0 s' s'' HInl0sc1 Hexec_sc1 _ Hsc IHsc sc1' sc2' Pi.
move=> Hressc1 IHsc1' Hressc2 IHsc2 Hsc'; subst.
case: Hsc' => X Y; subst sc1' sc2'.
move=> l0' s0 h0 HPi_l0 [? ?]; subst.
move=> Y; subst s''.
move: (restrict_dom _ _ _ _ _ HInl0sc1 HPi_l0) => X.
destruct s' as [ [l' [s' h'] ] | ].
- move: (proj2 (IHsc1' _ _ _ X) _ _ _ Hexec_sc1).
move/(IHsc _ _ _ Hressc1 IHsc1' Hressc2 IHsc2 (refl_equal _) _ _ _); tauto.
- move: {IHsc1'}(proj1 (IHsc1' _ _ _ X)); tauto.
+ move=> sc1 sc2 l0 st0 s' s'' HInl0sc2 Hexec_sc2 _ Hexec_sc IHsc sc1' sc2' Pi.
move=> Hressc1 IHsc1' Hressc2 IHsc2 Hsc'; subst.
case: Hsc' => X Y; subst sc1' sc2'.
move=> l0' s0 h0 HPi_l0 [? ?]; subst.
destruct s' as [ [ l' [s' h'] ] | ].
- move=> Y; subst s''.
move: (restrict_dom _ _ _ _ _ HInl0sc2 HPi_l0) => X.
move: (proj2 (IHsc2 _ _ _ X) _ _ _ Hexec_sc2).
move/(IHsc _ _ _ Hressc1 IHsc1' Hressc2 IHsc2 (refl_equal _) _ _ _); tauto.
- move: (restrict_dom _ _ _ _ _ HInl0sc2 HPi_l0) => X.
move: {IHsc2}(proj1 (IHsc2 _ _ _ X)); tauto.
+ move=> l' s' h' Hexec .
move Hst0 : (Some (l0, (s0, h0))) => st0.
move Hst' : (Some (l', (s', h'))) => st'.
move Hsc : (sc1[+]sc2) => sc.
rewrite Hst0 Hst' Hsc in Hexec.
move: Hexec sc1 sc2 P Hsc0 IHsc0 Hsc1 IHsc1 Hsc l0 s0 h0 l' s' h' HP_l0 Hst0 Hst'.
elim => //; move=> {sc st0 st'}.
+ move=> sc1 sc2 l0 st0 s' s'' HInl0sc1 Hexec_sc1 _ Hsc IHsc sc1' sc2' Pi.
move=> Hressc1 IHsc1' Hressc2 IHsc2 Hsc'; subst.
case: Hsc' => X Y; subst sc1' sc2'.
move=> l0' s0 h0 l'_ s'0 h' HPi_l0 [? ?]; subst => Y.
move: (restrict_dom _ _ _ _ _ HInl0sc1 HPi_l0) => X.
destruct s'' as [ [l'' [s'' h'']] | ] => //.
case: Y => ? ? ?; subst.
destruct s' as [ [l' [s' h']] | ].
- move: ((proj2 (IHsc1' _ _ _ X)) _ _ _ Hexec_sc1) => H.
by move: {IHsc1' IHsc2 IHsc} (IHsc _ _ _ Hressc1 IHsc1' Hressc2 IHsc2 (refl_equal _) _ _ _ _ _ _ H (refl_equal _) (refl_equal _)).
- by inversion Hsc.
+ move=> sc1 sc2 l0 st0 s' s'' HInl0sc2 Hexec_sc2 _ Hexec_sc IHsc sc1' sc2' Pi.
move=> Hressc1 IHsc1' Hressc2 IHsc2 Hsc'; subst.
case: Hsc' => X Y; subst sc1' sc2'.
move=> l0' s0 h0 l'_ s'_ h'_ HPi_l0 [? ?]; subst.
destruct s' as [ [l' [s' h']] | ].
- destruct s'' as [ [l'' [s'' h'']] | ] => //.
case=> ? ? ?; subst.
move: (restrict_dom _ _ _ _ _ HInl0sc2 HPi_l0) => X.
move: (proj2 (IHsc2 _ _ _ X) _ _ _ Hexec_sc2) => H.
by move: {IHsc1' IHsc2 IHsc} (IHsc _ _ _ Hressc1 IHsc1' Hressc2 IHsc2 (refl_equal _) _ _ _ _ _ _ H (refl_equal _) (refl_equal _)).
- by inversion Hexec_sc.
+ move=> sc l st HnotInlsc sc1 sc2 Pi Hressc1 IHsc1 Hressc2 IHsc2 Hsc l0 s0 h0 l' s' h' HP_l0 [? ?]; subst.
case=> ? ? ?; by subst.
- move=> sc P Q P' Q' HP HQ Hsc IH l0 s0 h0 HP_l0; split.
+ move=> X.
move: (HP _ _ _ HP_l0) => H2.
by move: (proj1 (IH _ _ _ H2) X).
+ move=> l' s' h' Hexec .
move: (HP _ _ _ HP_l0) => H2.
move: (proj2 (IH _ _ _ H2) _ _ _ Hexec) => H4.
by apply HQ.
Qed.
The semantic definition of the weakest precondition from [Saabas&Uustalu2007].
The additional conjunct is to take errors into account.
Definition wlp_semantics (sc : scode) (Pi : assn) : assn := fun l s h =>
~ (Some (l, (s, h)) >- sc ---> None) /\
forall l' s' h', Some (l, (s, h)) >- sc ---> Some (l', (s', h')) -> Pi l' s' h'.
Lemma 11 in [Saabas&Uustalu2007]:
Lemma wlp_completeness : forall sc (Hwf : wellformed sc) Q, [^ wlp_semantics sc Q ^] sc [^ Q ^].
Proof.
elim .
- move=> Hwf Q.
apply hoare_sgoto_conseq with (P':=wlp_semantics sO Q) (Q':=wlp_semantics sO Q); last by apply hoare_sO.
+ by move=> *.
+ move=> l s0 h0 Hwlp; by apply (proj2 Hwlp), exec_sgoto_refl.
- move=> l c Hwf Q.
apply hoare_sgoto_conseq with (P':= fun pc s h =>
pc = l /\ (wp0 c (Q (S l))) s h \/
pc <> l /\ Q pc s h) (Q' := Q); last by apply hoare_cmd.
+ move=> l0 s0 h0 Hwlp.
have [l0_l | l_l0] : l0 = l \/ l <> l0 by unfold label; lia.
* left; subst; split => //.
rewrite /wlp_semantics in Hwlp.
case: (cmd0_terminate c (s0, h0)) => s' Hs'.
destruct s' as [[s h]|].
- eapply exec0_wp0; [by apply Hs' | idtac].
apply (proj2 Hwlp).
eapply exec_sgoto_cmd0; eauto.
by constructor.
- case: Hwlp => H H0.
have : Some (l, (s0, h0)) >- sC l c ---> None by do 2 constructor.
contradiction.
* right; split; auto.
rewrite /wlp_semantics in Hwlp.
apply (proj2 Hwlp), exec_sgoto_refl => /=; tauto.
+ by rewrite /while.entails.
- move=> l [].
+ move=> j Hwf Q.
apply hoare_sgoto_conseq with (P' := fun pc s h =>
pc = l /\ (Q j s h \/ j = l) \/
pc <> l /\ Q pc s h) (Q' := Q); last by apply hoare_jmp.
* move=> l0 s0 h0 Hwlp.
have [l0_l | l_l0] : l0 = l \/ l <> l0 by unfold label; lia.
- subst; left; split => //.
rewrite /wlp_semantics in Hwlp.
have [j_l | j_l] : j = l \/ j <> l by unfold label; lia.
+ by subst; auto.
+ left; apply (proj2 Hwlp).
by eapply exec_sgoto_jmp; eauto.
- right; split; auto.
rewrite /wlp_semantics in Hwlp.
apply (proj2 Hwlp), exec_sgoto_refl => /=; tauto.
* by rewrite /while.entails.
+ move=> t j Hwf Q.
apply hoare_sgoto_conseq with (P':= fun pc s h => pc = l /\
(~~ eval_b t (s, h) /\ Q (S l) s h \/
eval_b t (s, h) /\ ( Q j s h \/ j = l)) \/
pc <> l /\ Q pc s h) (Q' := Q); last by apply hoare_branch.
+ move=> l0 s0 h0 Hwlp.
have [l0_l | l_l0] : l0 = l \/ l <> l0 by unfold label; lia.
* subst; left; split => //.
case/boolP : (eval_b t (s0, h0)) => Heval.
- right; split => //.
have [j_l | j_l] : j = l \/ j <> l by unfold label; lia.
- subst; by right.
- left; apply (proj2 Hwlp).
by eapply exec_sgoto_cjmp_true; eauto.
- left; split; first by [].
rewrite /wlp_semantics in Hwlp.
apply (proj2 Hwlp).
by eapply exec_sgoto_cjmp_false; eauto.
* right; split; first by auto.
apply (proj2 Hwlp), exec_sgoto_refl => /=; tauto.
+ by rewrite /while.entails.
- move=> sc0 IHsc0 sc2 IHsc1 Hwf Q.
apply hoare_sgoto_conseq with (P' := wlp_semantics (sc0 [+] sc2) Q)
(Q' := restrict_cplt (wlp_semantics (sc0 [+] sc2) Q) (sdom (sc0 [+] sc2))).
+ by rewrite /while.entails.
+ move=> l s h.
rewrite /restrict_cplt /wlp_semantics; case=> Hres1 Hres2.
by apply (proj2 Hres2), exec_sgoto_refl.
+ apply hoare_sS.
* apply hoare_sgoto_conseq with (P' := wlp_semantics sc0 (wlp_semantics (sc0 [+] sc2) Q))
(Q' := wlp_semantics (sc0 [+] sc2) Q).
- move=> l s h.
rewrite /restrict /while.And; case=> H2 l_sc0; split.
+ rewrite /wlp_semantics in H2.
case: H2 => H H0.
contradict H.
eapply exec_sgoto_seq0; eauto.
by constructor.
+ move=> l' s' h' Hsc0; split.
* rewrite /wlp_semantics in H2.
case: H2 => H H0.
contradict H.
by eapply exec_sgoto_seq0; eauto.
* move=> l'' s'' h'' Hsc.
apply (proj2 H2).
by eapply exec_sgoto_seq0; eauto.
- by rewrite /while.entails.
- apply IHsc0.
by eapply wellformed_inv_L; eauto.
* apply hoare_sgoto_conseq with (P' := wlp_semantics sc2 (wlp_semantics (sc0 [+] sc2) Q))
(Q' := wlp_semantics (sc0 [+] sc2) Q).
- move=> l s h.
rewrite /restrict /while.And; case=> H2 l_sc2; split.
+ rewrite /wlp_semantics in H2.
case : H2 => H H0.
contradict H.
eapply exec_sgoto_seq1; eauto.
by constructor.
+ move=> l' s' h' Hsc2; split.
* rewrite /wlp_semantics in H2.
case: H2 => H H0.
contradict H.
by eapply exec_sgoto_seq1; eauto.
* move=> l'' s'' h'' Hsc.
apply (proj2 H2).
by eapply exec_sgoto_seq1; eauto.
- by rewrite /while.entails.
- apply IHsc1.
by eapply wellformed_inv_R; eauto.
Qed.
Theorem 12 (Completeness) in [Saabas&Uustalu2007].
Lemma hoare_sgoto_complete : forall (P Q : assn) sc (Hwf : wellformed sc),
(forall l s h, P l s h ->
~ Some (l, (s, h)) >- sc ---> None /\
(forall l' s' h', Some (l,(s,h)) >- sc ---> Some (l',(s',h')) -> Q l' s' h')) ->
[^ P ^] sc [^ Q ^].
Proof.
move=> P Q sc Hwf Hsemax.
apply hoare_sgoto_conseq with (P' := wlp_semantics sc Q) (Q' := Q).
- move=> l s h HP.
rewrite /wlp_semantics; split.
+ by apply (proj1 (Hsemax _ _ _ HP)).
+ move=> l' s' h' Hexec.
by apply (proj2 (Hsemax _ _ _ HP)).
- by rewrite /while.entails.
- by apply wlp_completeness.
Qed.
End SGoto_Hoare.