Module HLD:=HD.
Definition sem_wp := wp.
Export Wf.
(** * Syntactic definition of the weakest precondition.  In the following, we show that this definition is logically equivalent to [wp]. *)
Fixpoint synt_wp (prog: ImpProg) : Pred -> Pred
:= fun post e =>
match prog with
| Iskip => post e
| (Iset A x expr) => post (E.upd x (E.eval expr e) e)
| (Iif cond p1 p2) =>
((E.eval cond e)=true -> (synt_wp p1 post e))
/\ ((E.eval cond e)=false -> (synt_wp p2 post e))
| (Iseq p1 p2) => synt_wp p1 (synt_wp p2 post) e
| (Iwhile cond p) =>
exists inv:Pred,
exists R:E.Env -> E.Env -> Prop,
(well_founded R)
/\ (inv e)
/\ (forall e', (inv e')
-> (E.eval cond e')=false -> post e')
/\ (forall e', (inv e')
-> (E.eval cond e')=true -> synt_wp p inv e')
/\ (forall e0, (inv e0)
-> (E.eval cond e0)=true -> synt_wp p (fun e1 => R e1 e0) e0)
end.
(** * Soundness *)
Hint Resolve synt_wp_monotonic: hoare.
(** Below, a little tactic to decompose a pair in hypothesis [H] by giving the name [n] to the first component. *)
Ltac dec2 n H := case H; clear H; intros n H.
(** * Auxiliary lemmas for completeness  The proof of completeness requires to exhibit a variant. The purpose of the following lemmas is to build this variant. *)
(** ** A technical issue: the inversion of [exec]  If your are not interested in Coq details, you may skip this part which only explains how to avoid the assumption of a (consistent and standard) axiom to prove the completeness.  Because the use of dependent types in constructor [exec_Iset], the standard inversion of Coq may fail on [exec] (see [exec_test_inversion] below).  This comes from the fact the following property is not provable in the core theory of Coq (although it is consistent with it) :  [forall A (x1 x2:E.Var A) e1 e2, (Iset x1 e1)=(Iset x2 e2) -> x1=x2 /\ e1=e2.]  To deal with this problem, we may assume a (consistent) axiom given in #<a href=http://coq.inria.fr/V8.1/stdlib/Coq.Logic.EqdepFacts.html># [EqdepFacts]#</a>#. But here, we can avoid this axiom.  Indeed, I define an ad-hoc inversion lemma for [exec] called [exec_inversion] below. This lemma is directly derived from the notion of weakest liberal precondition: [aux_wlp] is an other alternative definition of [wlp].  *)
Definition aux_wlp (prog: ImpProg) : Pred -> Pred
:= fun post e =>
match prog with
| Iskip => post e
| (Iset A x expr) => post (E.upd x (E.eval expr e) e)
| (Iif cond p1 p2) =>
forall e', exec e (if E.eval cond e then p1 else p2) e'
-> post e'
| (Iseq p1 p2) => forall e1 e2, exec e p1 e1 -> exec e1 p2 e2 -> post e2
| (Iwhile cond p) => forall e', exec e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e' -> post e'
end.
(** Below, a little tactic to helps in applying [exec_inversion]. *)
Ltac exec_inversion H :=
match type of H with
| (exec ?e ?p ?e') => pattern e'; apply (exec_inversion H); simpl; clear H
end.
(** ** Definition of the variant Given a program [p] and a boolean expression [cond], the relation on environment "[reduces cond p]" is the variant required by "[synt_wp (Iwhile cond p)]".  I prove below that this relation is well-founded. *)
Definition reduces cond p e1 e0 :=
(E.eval cond e0)=true /\ (exec e0 p e1) /\ exists ef, (exec e1 (Iwhile cond p) ef).
(** To prove that "[reduces cond p]" is well-founded, I want to count the number of execution of [p] in the computation of "[Iwhile cond p]". Indeed, as the language is deterministic, this number is unique.  Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" in a sequence of [n] execution of [p]. *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
| execn_Iskip:
forall e, (execn 0 e Iskip e)
| execn_Iset:
forall (A:Type) e x (expr: E.Expr A),
(execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
| execn_Iif:
forall n e (cond: E.Expr bool) p1 p2 e',
(execn n e (if (E.eval cond e) then p1 else p2) e')
-> (execn n e (Iif cond p1 p2) e')
| execn_Iseq:
forall n e p1 p2 e' e'',
(exec e p1 e')
-> (execn n e' p2 e'')
-> (execn n e (Iseq p1 p2) e'')
| execn_Iwhile:
forall n e cond p e',
(execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
-> (execn (S n) e (Iwhile cond p) e').
Hint Resolve execn_Iskip execn_Iset execn_Iif execn_Iseq execn_Iwhile: hoare.
Hint Resolve reduces_wf: hoare.
(** * Combining the previous results with transitivity of [ |= ] *)
Hint Resolve wp_complete wp_sound: hoare.

Theorem soundness: forall pre p post, pre |= (synt_wp p post) -> pre |= p [=post=].